﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Reflection;
using daDataLayer;
using System.IO;

namespace danalyser.Interface.Forms
{
    // Контроллеры, объекты и свойства
    using daBase.Objects;
    using daBase.Objects.Metrics;
    using Controllers;
    using daBase.Objects.AnalysisErrors;
    using Properties;
    using Dialogs;

    /// <summary>
    /// Главная форма
    /// </summary>
    public partial class mainForm : Form
    {
        // Уровни важности ошибок
        private Dictionary<ErrorLevel, Bitmap> levels;
        private Dictionary<ErrorLevel, string> level_desc;

        // Выбор директории
        private FolderBrowserDialog folderBrowser;
        private ToolTip hints;

        // Текущая ошибка
        private DataGridViewRow current;

        /// <summary>
        /// Обработчик события "стадия анализа изменилась"
        /// </summary>
        /// <param name="sender">инициатор события</param>
        /// <param name="e">информация о стадии анализа</param>
        private void StageChanged(object sender, MessageArgs e)
        {
            FormController.Instance.Splash.Operation = e.Message;
        }

        /// <summary>
        /// Получить ссылку на обозреватель директорий (по ленивой стратегии)
        /// </summary>
        /// <returns>обозреватель директорий</returns>
        private FolderBrowserDialog GetFolderBrowser()
        {
            if (folderBrowser == null)
                folderBrowser = new FolderBrowserDialog();
            return folderBrowser;
        }

        /// <summary>
        /// Синхронизация списка файлов
        /// </summary>
        private void Sync()
        {
            foreach (string filename in FileController.Instance.FileNames)
            {
                if (!fileBox.Items.Contains(filename))
                    fileBox.Items.Add(filename);
            }
        }

        /// <summary>
        /// Состояние анализатора
        /// </summary>
        /// <param name="stateName">сообщение состояния</param>
        private void ToState(string stateName)
        {
            status.Text = string.Format("{0} (файлов {1}, ошибок {2})", stateName, fileBox.Items.Count, errorBox.Rows.Count);
            this.Update();
        }

        /// <summary>
        /// Сброс состояния анализатора
        /// </summary>
        private void ResetState()
        {
            ToState("Готово");
        }

        /// <summary>
        /// Можно ли начать анализ
        /// </summary>
        private void CanStart()
        {
            bool can = fileBox.Items.Count > 0;
            startBtn.Enabled = can;
            начатьАнализToolStripMenuItem.Enabled = can;
            открытьToolStripMenuItem.Enabled = can;
            открытьToolStripMenuItem2.Enabled = can;
            открытьToolStripMenuItem5.Enabled = can;
            удалитьВыделенныеToolStripMenuItem.Enabled = can;
            удалитьВыделенныеToolStripMenuItem1.Enabled = can;
            удалитьВсеToolStripMenuItem.Enabled = can;
            удалитьВсеToolStripMenuItem1.Enabled = can;
            удалитьToolStripMenuItem.Enabled = can;
            очиститьToolStripMenuItem1.Enabled = can;
        }

        /// <summary>
        /// Можно ли произвести экспорт
        /// </summary>
        private void CanExport()
        {
            bool can = errorBox.Rows.Count > 0;
            exportBtn.Enabled = can;
            экспортироватьсписокошибокToolStripMenuItem.Enabled = can;
            экспортироватьсписокошибокToolStripMenuItem2.Enabled = can;
            открытьToolStripMenuItem1.Enabled = can;
            открытьToolStripMenuItem3.Enabled = can;
            открытьToolStripMenuItem4.Enabled = can;
            удалитьToolStripMenuItem1.Enabled = can;
            удалитьВыделенныеToolStripMenuItem2.Enabled = can;
            удалитьВыделенныеToolStripMenuItem3.Enabled = can;
            удалитьВсеToolStripMenuItem2.Enabled = can;
            удалитьВсеToolStripMenuItem3.Enabled = can;
            очиститьToolStripMenuItem.Enabled = can;
        }

        /// <summary>
        /// Добавление файла/директории
        /// </summary>
        /// <param name="Filename">имя файла/директории</param>
        private void AddFiles(string FileName)
        {
            ToState("Добавление файлов");
            FormController.Instance.Splash.Operation = "Добавление файлов";
            FormController.Instance.Splash.ShowInCenterOf(this);
            FileController.Instance.Add(FileName);
            Sync();
            ResetState();
            FormController.Instance.Splash.Hide();
        }

        /// <summary>
        /// Конструктор
        /// </summary>
        public mainForm()
        {
            InitializeComponent();
            hints = new ToolTip();
//            errorBox.too
            levels = new Dictionary<ErrorLevel, Bitmap>();
            level_desc = new Dictionary<ErrorLevel, string>();
            levels.Add(ErrorLevel.Hint, Resources.Information);
            levels.Add(ErrorLevel.Alert, Resources.Warning);
            levels.Add(ErrorLevel.Error, Resources.Critical);
            level_desc.Add(ErrorLevel.Hint, "Подсказка");
            level_desc.Add(ErrorLevel.Alert, "Предупреждение");
            level_desc.Add(ErrorLevel.Error, "Критическая ощибка");
            foreach (Bitmap icon in levels.Values)
                icon.MakeTransparent(icon.GetPixel(0, 0));
            Sync();
            CanStart();
            CanExport();
            current = null;
            AnalysisController.Instance.StageChangedEvent += new EventHandler<MessageArgs>(StageChanged);
        }

        /// <summary>
        /// Экспорт списка ошибок
        /// </summary>
        private void экспортироватьсписокошибокToolStripMenuItem_Click(object sender, EventArgs e)
        {
            saveFile.FileName = "";
            if (saveFile.ShowDialog() != DialogResult.Cancel)
                AnalysisController.Instance.Export(saveFile.FileName);
        }

        /// <summary>
        /// Общие настройки
        /// </summary>
        private void настройкиToolStripMenuItem_Click(object sender, EventArgs e)
        {
            MainSettingsForm temp = new MainSettingsForm();
            temp.ShowDialog();
            //FormController.Instance.MainSettings.ShowDialog();
        }

        /// <summary>
        /// Выход
        /// </summary>
        private void выходToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        /// <summary>
        /// Добавление файла
        /// </summary>
        private void поОдномуToolStripMenuItem_Click(object sender, EventArgs e)
        {
            openFile.FileName = "";
            if (openFile.ShowDialog() != DialogResult.Cancel)
                AddFiles(openFile.FileName);
            CanStart();
        }

        /// <summary>
        /// Добавление директории
        /// </summary>
        private void целуюДиректориюToolStripMenuItem_Click(object sender, EventArgs e)
        {
            folderDialog.SelectedPath = "";
            if (folderDialog.ShowDialog() != DialogResult.Cancel)
                AddFiles(folderDialog.SelectedPath);
            CanStart();
        }

        /// <summary>
        /// Удаление выделенных файлов
        /// </summary>
        private void удалитьВыделенныеToolStripMenuItem_Click(object sender, EventArgs e)
        {
            List<string> files = new List<string>();
            foreach (string file in fileBox.SelectedItems)
                files.Add(file);
            foreach (string file in files)
            {
                FileController.Instance.Remove(file);
                fileBox.Items.Remove(file);
            }
            CanStart();
        }

        /// <summary>
        /// Удаление всех файлов
        /// </summary>
        private void удалитьВсеToolStripMenuItem_Click(object sender, EventArgs e)
        {
            FileController.Instance.Clear();
            fileBox.Items.Clear();
            CanStart();
        }

        /// <summary>
        /// Открытие файла в редакторе кода
        /// </summary>
        private void открытьToolStripMenuItem2_Click(object sender, EventArgs e)
        {
            current = null;
            if (fileBox.SelectedItems.Count > 0)
                FormController.Instance.Editor.ShowLoad(fileBox.SelectedItems[0].ToString());
            else if (fileBox.Items.Count > 0)
                FormController.Instance.Editor.ShowLoad(fileBox.Items[0].ToString());
        }

        private void ShowError(DataGridViewRow row)
        {
            current = row;
            errorBox.ClearSelection();
            row.Selected = true;
            ParsingError error = row.Tag as ParsingError;
            string hint = error.Hint;
            if (error.Code != string.Empty) hint += string.Format("\r\n\r\nКод, содержащий ошибку:\r\n{0}", error.Code);
            FormController.Instance.Editor.ShowLoad(error.File, error.Line, hint, true);
        }

        /// <summary>
        /// Открытие файла содержащего ошибку
        /// </summary>
        private void открытьToolStripMenuItem3_Click(object sender, EventArgs e)
        {
            if (errorBox.SelectedRows.Count > 0)
                ShowError(errorBox.SelectedRows[0]);
        }

        /// <summary>
        /// Удаление выделенных ошибок
        /// </summary>
        private void удалитьВыделенныеToolStripMenuItem2_Click(object sender, EventArgs e)
        {
            List<int> errors = new List<int>();
            foreach (DataGridViewRow row in errorBox.SelectedRows)
                errors.Add(row.Index);
            errors.Sort();
            errors.Reverse();
            for (int i = 0; i < errors.Count; i++)
            {
                errorBox.Rows.RemoveAt(errors[i]);
                AnalysisController.Instance.RomoveErrorAt(errors[i]);
            }
            CanExport();
        }

        /// <summary>
        /// Очистка списка ошибок
        /// </summary>
        private void удалитьВсеToolStripMenuItem2_Click(object sender, EventArgs e)
        {
            errorBox.Rows.Clear();
            CanExport();
        }

        /// <summary>
        /// Старт анализа
        /// </summary>
        private void начатьАнализToolStripMenuItem_Click(object sender, EventArgs e)
        {
            FormController.Instance.Splash.Operation = "Подготовка";
            FormController.Instance.Splash.ShowInCenterOf(this);
            ToState("Подготовка");
            bool analyse = (Settings.Default.askToSaveFormatted && (MessageBox.Show("Сохранить отформатированный код после анализа?", "Сохранять?", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes));
            string saveFormattedTo = string.Empty;
            if (analyse)
            {
                if (analyse = (GetFolderBrowser().ShowDialog() == DialogResult.OK))
                    saveFormattedTo = GetFolderBrowser().SelectedPath;
            }
            else analyse = true;
            if (analyse)
            {
                ToState("Анализ");
                current = null;
                errorBox.Rows.Clear();
                AnalysisController.Instance.Analyse(Settings.Default.LoadModulesIfNeed, saveFormattedTo);
                int i = 0;
                foreach (ParsingError error in AnalysisController.Instance.Errors)
                {
                    errorBox.Rows.Add(++i, levels[error.WarningLevel], level_desc[error.WarningLevel], error.Level, error.Message, new FileInfo(error.File).Name, error.MetaTags["author"], error.File, error.Line);
                    errorBox.Rows[i - 1].Cells["File"].ToolTipText = errorBox.Rows[i - 1].Cells["FullFileName"].Value.ToString();
                    errorBox.Rows[i - 1].Tag = error;
                }
                CanExport();

                MetricBox.Rows.Clear();
                foreach (Metrica metr in AnalysisController.Instance.Metrics)
                {
                    MetricBox.Rows.Add();
                    MetricBox[0, MetricBox.RowCount - 1].Value = MetricBox.RowCount;
                    MetricBox[1, MetricBox.RowCount - 1].Value = metr.Name;
                    MetricBox[2, MetricBox.RowCount - 1].Value = metr.Value;
                    //String[] strs = metr.File.Split((char)0x5C);
                    MetricBox[3, MetricBox.RowCount - 1].Value = metr.Object;//strs[strs.Length - 1];
                    MetricBox[4, MetricBox.RowCount - 1].Value = metr.File;
                    MetricBox[5, MetricBox.RowCount - 1].Value = metr.Line;
                }

                MessageBox.Show(string.Format("Проверка завершена!\r\nЗамечаний: {0}", i));
            }
            errorBox.ScrollBars = ScrollBars.None;
            MetricBox.ScrollBars = ScrollBars.None;

            errorBox.ScrollBars = ScrollBars.Vertical;
            MetricBox.ScrollBars = ScrollBars.Vertical;
            
            FormController.Instance.Splash.Hide();
            ResetState();
        }

        /// <summary>
        /// Настройка статических анализаторов
        /// </summary>
        private void настройкиАнализатораToolStripMenuItem_Click(object sender, EventArgs e)
        {
            AnalysersSettingsForm temp = new AnalysersSettingsForm();
            temp.ShowDialog();
            //FormController.Instance.AnalyserSettings.ShowDialog();
        }

        /// <summary>
        /// Отображение редактора кода
        /// </summary>
        private void редакторКодаToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (FormController.Instance.Editor.Visible) FormController.Instance.Editor.Focus();
            else FormController.Instance.Editor.ShowClear();
        }

        /// <summary>
        /// Клик по пункту меню "О Программе"
        /// </summary>
        private void оПрограммеToolStripMenuItem_Click(object sender, EventArgs e)
        {
            FormController.Instance.About.ShowDialog();
        }

        /// <summary>
        /// Отображение автора в списке ошибок
        /// </summary>
        private void авторToolStripMenuItem_Click(object sender, EventArgs e)
        {
            errorBox.Columns["Author"].Visible = !errorBox.Columns["Author"].Visible;
            авторToolStripMenuItem.Checked = errorBox.Columns["Author"].Visible;
        }

        /// <summary>
        /// Нажатие кнопки над списком файлов
        /// </summary>
        private void fileBox_KeyDown(object sender, KeyEventArgs e)
        {
            switch (e.KeyCode)
            {
                case Keys.Enter:
                    открытьToolStripMenuItem2_Click(sender, new EventArgs());
                    break;
                case Keys.Delete:
                    удалитьВыделенныеToolStripMenuItem_Click(sender, new EventArgs());
                    break;
            }
        }

        /// <summary>
        /// Начало перетаскивания файлов на форму
        /// </summary>
        private void fileBox_DragEnter(object sender, DragEventArgs e)
        {
            e.Effect = (e.Data.GetDataPresent(DataFormats.FileDrop)) ? DragDropEffects.All : DragDropEffects.None;
            CanStart();
        }

        /// <summary>
        /// Файлы перекинуты на форму
        /// </summary>
        private void fileBox_DragDrop(object sender, DragEventArgs e)
        {
            ToState("Добавление файлов");
            FormController.Instance.Splash.Operation = "Добавление файлов";
            FormController.Instance.Splash.ShowInCenterOf(this);
            string[] filenames = (string[])e.Data.GetData(DataFormats.FileDrop, false);
            foreach (string filename in filenames)
                FileController.Instance.Add(filename);
            Sync();
            CanStart();
            ResetState();
            FormController.Instance.Splash.Hide();
        }

        /// <summary>
        /// Нажатие кнопки над списком ошибок
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void errorBox_KeyDown(object sender, KeyEventArgs e)
        {
            switch (e.KeyCode)
            {
                case Keys.Enter:
                    открытьToolStripMenuItem3_Click(sender, new EventArgs());
                    e.Handled = true;
                    break;
                case Keys.Delete:
                    удалитьВыделенныеToolStripMenuItem2_Click(sender, new EventArgs());
                    break;
            }
        }

        /// <summary>
        /// Показать предыдущую ошибку
        /// </summary>
        public bool ShowPrevError()
        {
            if (current == null) return false;
            if (current.Index == 0)
                ShowError(errorBox.Rows[errorBox.Rows.Count - 1]);
            else ShowError(errorBox.Rows[current.Index - 1]);
            return true;
        }

        /// <summary>
        /// Показать следующую ошибку
        /// </summary>
        public bool ShowNextError()
        {
            if (current == null) return false;
            if (current.Index == errorBox.Rows.Count - 1)
                ShowError(errorBox.Rows[0]);
            else ShowError(errorBox.Rows[current.Index + 1]);
            return true;
        }

        private void ReCheckErrorsBox() { }

        private void errorBox_Sorted(object sender, EventArgs e)
        {
            ReCheckErrorsBox();
        }

        private void errorBox_RowsRemoved(object sender, DataGridViewRowsRemovedEventArgs e)
        {
            ReCheckErrorsBox();
        }

        private void cQLзапросыToolStripMenuItem_Click(object sender, EventArgs e)
        {
            CQLQueries1 temp = new CQLQueries1();
            temp.ShowDialog();
        }

        private void errorBox_CellContentClick(object sender, DataGridViewCellEventArgs e)
        {
        }

        private void errorBox_CellContentDoubleClick(object sender, DataGridViewCellEventArgs e)
        {
            if (errorBox.SelectedRows.Count > 0)
                ShowError(errorBox.SelectedRows[0]);
        }

        private void MetricBox_CellContentDoubleClick(object sender, DataGridViewCellEventArgs e)
        {
            if (MetricBox.SelectedRows.Count > 0)
            {
                FormController.Instance.Editor.ShowLoad(MetricBox[4, e.RowIndex].Value.ToString(), Convert.ToInt32(MetricBox[5, e.RowIndex].Value), "test", true);
            }
        }
    }
}
